/*!
 * vinculum
 * Copyright(c) 2017 azzly
 * MIT Licensed
 */
 
'use strict';

/**
 * Module dependencies.
 * @private
 */
const helper = require("../helper");
const CONST = require("../CONST");
const config = require("../config");
const debug = require("../debug")(__filename);
const error = require("../HTTPErrors");
const datasource = require("../datasource");
const service = require('../oo/service');
const action = require('../oo/action');
const application = require('../oo/application');

/**
 * private funciton.
 **/

function auth_admin(req,res,next){
	let user = req.vinculum.session.getUser();
	if(user.id === config.administrator.id){
		next();
	}else{
		res.vinculum.error(error.UNAUTHORIZED);
	}
}


function auth_user(req,res,next){
	let user = req.vinculum.session.getUser();
	if(!!user){
		next();
	}else{
		res.vinculum.error(error.UNAUTHORIZED);
	}
}

function _auth_authoriztion(params,req){
  return new Promise((resolve, reject)=>{
    datasource.systemQuery(CONST.SQLS.authorization_browse,[params.whatid,params.whattype]).then(result=>{
      if(result.length === 0){
				resolve(true);
			}else{
				let user_roles = req.vinculum.session.getUserRoles();
				let isvalid = false;
				for(let one_result of result){
					for(let one_user_role of user_roles){
						if(one_result.roleid === one_user_role){
							isvalid = true;
							break;
						}
					}
					if(isvalid){
						break;
					}
				}
        resolve(isvalid);
			}
    }).catch(err=>{
      reject(err);
    });
  });
}

const LIMITTIME = 5 * 60 * 1000;
function _app_auth(params,whatid,whattype){
	return new Promise((resolve, reject)=>{
		if(!params.appid){
			reject('need appid');
		}else if(!params.timestamp){
			reject('need timestamp');
		}else if(!params.sign){
			reject('need sign');
		}else{
			let datenow = Date.now();
			let daterequest = new Date(parseInt(params.timestamp));
			if(!daterequest.getTime()) {
				reject('invalid timestamp!');
			}else if((datenow - params.timestamp) <=0 
				|| (datenow - params.timestamp) > LIMITTIME){
				reject('timestamp out!');
			}else{
				datasource.systemQuery(CONST.SQLS.third_party_browse
					,[params.appid,whatid,whattype]).then(result=>{
					if(result.length === 0){
						return Promise.reject('invalid appid!' + params.appid);
					}
					let appinfo = result[0];
					let signstr = [];
					signstr.push(params.appid);
					signstr.push(appinfo.appsecret);
					signstr.push(params.timestamp);
					if(params.sign !== helper.sha1(signstr.join(''))){
						return Promise.reject('invalid sign!');
					}
					resolve(appinfo);
				}).catch(err=>{
					reject(err);
				});
			}
		}
	});
}

function auth_dobo(info,req){
	let auth_type = req.params.type;
	let auth_id = req.params.id;
		
	if(info.isfilter === CONST.FILTER_TYPES.ROLE){
		return _auth_authoriztion({whatid:info.id,whattype:auth_type},req);
	}else if(info.isfilter === CONST.FILTER_TYPES.ROOT){
		let user = req.vinculum.session.getUser();
		return Promise.resolve(user.id === config.administrator.id);
	}else if(info.isfilter === CONST.FILTER_TYPES.USER){
		let user = req.vinculum.session.getUser();
		return Promise.resolve(!!user.id);
	}else if(info.isfilter === CONST.FILTER_TYPES.APP){
		return _app_auth(req.vinculum.params,info.id,auth_type);
	}else{
		return Promise.resolve(true);
	}
}
 
/**
 * module.
 */

module.exports = ()=>{
  return (req,res,next)=>{
		let auth_type = req.params.type;
		let auth_id = req.params.id;
		let dobo;
		switch(auth_type){
			case 'cron': 
			case 'clearCache':
				auth_admin(req,res,next);
				break;			
			case 'loginOut': 
				auth_user(req,res,next);
				break;
			case 'service': 
				dobo = service;
			case 'action':
				if(!dobo) dobo = action;
			case 'application':
				if(!dobo) dobo = application;
				let ginfo;
				dobo.find(auth_id).then(info=>{
					ginfo = info;
					return auth_dobo(info,req,res);
				}).then(isauthed=>{
					if(isauthed) {
						next();
					}else if(auth_type === 'application' && ginfo.authurl){
						res.vinculum.redirect(ginfo.authurl);
					}else if(auth_type === 'application' && auth_id !== 'login'){
						res.vinculum.redirect('login?appname=' + auth_id);
					}else{
						return Promise.reject(error.UNAUTHORIZED);
					}
				}).catch(err=>{
					res.vinculum.error(err);
				});
				break;
			default: 
				next();
		}
  }
};